package com.ruoyi.game.core.card;


import com.ruoyi.game.constant.GameErrorCode;
import com.ruoyi.game.core.exception.GameOpException;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/*
 * 纸牌
 * */
public class BasePoker {
    public static enum	PockerColorType{
        POCKER_COLOR_TYPE_DIAMOND(0), 		//方块
        POCKER_COLOR_TYPE_CLUB(1), 		//梅花
        POCKER_COLOR_TYPE_SPADE(2), 		//红桃
        POCKER_COLOR_TYPE_HEART(3), 		//黑桃
        POCKER_COLOR_TYPE_TRUMP(4), 		//大小王
        ;
        private int value;
        private PockerColorType(int value) {this.value = value;}
        public int value() {return this.value;}
        public static PockerColorType valueOf(int value) {
            for (PockerColorType flow : PockerColorType.values()) {
                if (flow.value == value) {
                    return flow;
                }
            }
            return PockerColorType.POCKER_COLOR_TYPE_DIAMOND;
        }

        public static PockerColorType getOpType(String value) {
            String gameTypyName = value.toUpperCase();
            for (PockerColorType flow : PockerColorType.values()) {
                if (flow.toString().equals(gameTypyName)) {
                    return flow;
                }
            }
            return PockerColorType.POCKER_COLOR_TYPE_DIAMOND;
        }
    }

    public static enum PockerValueType{
        POCKER_VALUE_TYPE_SINGLE(0),			//单张
        POCKER_VALUE_TYPE_SUB(1),				//对子
        POCKER_VALUE_TYPE_THREE(2),				//三张一样(三条)
        POCKER_VALUE_TYPE_BOMB(3),				//四张一样 （炸弹）
        POCKER_VALUE_TYPE_FLUSH(4),				//同花
        POCKER_VALUE_TYPE_STRAIGHT_FLUSH(5),	//同花顺
        POCKER_VALUE_TYPE_SHUN_ZI(6),			//顺子

        ;
        private int value;
        private PockerValueType(int value) {this.value = value;}
        public int value() {return this.value;}
        public static PockerValueType valueOf(int value) {
            for (PockerValueType flow : PockerValueType.values()) {
                if (flow.value == value) {
                    return flow;
                }
            }
            return PockerValueType.POCKER_VALUE_TYPE_SUB;
        }

        public static PockerValueType getOpType(String value) {
            String gameTypyName = value.toUpperCase();
            for (PockerValueType flow : PockerValueType.values()) {
                if (flow.toString().equals(gameTypyName)) {
                    return flow;
                }
            }
            return PockerValueType.POCKER_VALUE_TYPE_SUB;
        }
    }

    public static enum PockerListType{
        POCKERLISTTYPE_AFIRST,   //a在前
        POCKERLISTTYPE_AEND,   //a在后
        POCKERLISTTYPE_TWOEND,   //2在后
    }

    //扑克牌(一副) a 最小
    public static Integer[] PockerList_AFirst = {
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, //方块A~K
            0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, //梅花A~K
            0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, //红桃A~K
            0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, //黑桃A~K
    };

    //扑克牌(一副) a 最大
    public static Integer[] PockerList_AEnd = {
            0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,//方块2~A
            0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E,//梅花2~A
            0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E,//红桃2~A
            0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E,//黑桃2~A
    };

    //扑克牌(一副) 2 最大
    public static Integer[] PockerList_TWOEnd = {
            0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, //方块3~2
            0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, //梅花3~2
            0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, //红桃3~2
            0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, //黑桃3~2
    };

    public static boolean isJoker(int card) {
        return getCardColor(card) == PockerColorType.POCKER_COLOR_TYPE_TRUMP.value();
    }

    public static boolean isZhuPai(int card, int zhuColor, int zhuValue) {
        return getCardValueEx(card) == zhuValue
                || (zhuColor != -1 && getCardColor(card) == zhuColor)
                || isDaWang(card) || isXiaoWang(card);
    }

    /** 是否是小王 */
    public static boolean isXiaoWang(int card) {
        return card == 0x41;
    }

    /** 是否是大王 */
    public static boolean isDaWang(int card) {
        return card == 0x42;
    }

    //扑克牌(一副)
    public static Integer[] Trump_PockerList = {
            0x41, 0x42 //大小王
    };

    //牌值掩码
    public static int LOGIC_MASK_VALUE = 0x0F;

    //花色掩码
    public static int LOGIC_MASK_COLOR = 0xF0;

    //牌数
    public static int MAX_NORMAL_POCKER = 52;

    //单色牌数
    public static int ONE_COLOR_POCKER_COUNT = 13;

    //王牌数
    public static int MAX_TRUMP_POCKER = 2;

    //顺子最少牌数
    public static int MIN_FLUSH_COUNT = 5;

    // 花色掩码 % 80
    public static int LOGIC_MASK_COLOR_MOD = 80;

    //获取牌值
    public static int getCardValue(int card)
    {
        int value = card & LOGIC_MASK_VALUE;
        return value;
    }

    public static int getCardValueEx(int card)
    {
        int value = card & LOGIC_MASK_VALUE;
        if (PockerColorType.POCKER_COLOR_TYPE_TRUMP.equals(PockerColorType.valueOf(getCardColor(card)))) {
            value += 0x10;
        }
        return value;
    }

    /**
     * 获取牌的比较值（用于连对/比大小，支持主2、副2、大小王等逻辑）
     * 主2 => 16
     * 副2 => 15
     * A~3 => 14~3
     * 小王 => 17
     * 大王 => 18
     */
    public static int getCardPower(int card, int zhuColor, int zhuValue) {
        int baseVal = getCardValue(card);       // 真实点数，如 2 = 2，A = 14
        int color = getCardColor(card);         // 花色

        if (isJoker(card)) {
            return card == 0x41 ? 17 : 18;      // 小王、大王
        }

        if (baseVal == zhuValue) {
            if (color == zhuColor) {
                return 16;                      // 主2
            } else {
                return 15;                      // 副2
            }
        }

        return baseVal;                         // 其他牌值照常返回
    }

    //获取掩码
    public static int getCardColor(int card)
    {
        int color = card & LOGIC_MASK_COLOR ;
        while (color >= LOGIC_MASK_COLOR_MOD) {
            color -= LOGIC_MASK_COLOR_MOD;
        }
        return color / 0x10 ;
    }

    public static String getCardDescription(int card) {
        if (isJoker(card)) {
            return card == 0x41 ? "小王" : "大王"; // 大小王
        }

        // 获取花色
        String color;
        switch (getCardColor(card)) {
            case 0:
                color = "方块";
                break;
            case 1:
                color = "梅花";
                break;
            case 2:
                color = "红桃";
                break;
            case 3:
                color = "黑桃";
                break;
            default:
                color = "未知";
                break;
        }

        // 获取牌值
        int value = getCardValue(card);
        String valueStr;
        if (value >= 2 && value <= 10) {
            valueStr = String.valueOf(value);
        } else {
            switch (value) {
                case 11:
                    valueStr = "J";
                    break;
                case 12:
                    valueStr = "Q";
                    break;
                case 13:
                    valueStr = "K";
                    break;
                case 14:
                    valueStr = "A";
                    break;
                default:
                    valueStr = "未知";
                    break;
            }
        }

        return color + valueStr;
    }

    /**
     * 转换牌列表为 “红桃K, 梅花2, 小王” 格式字符串
     */
    public static String toCardString(List<Integer> cards) {
        if (cards == null) {
            return "null";
        }
        return cards.stream()
                .map(BasePoker::getCardDescription)
                .collect(Collectors.joining(", "));
    }

    /**
     * 根据亮主出的牌，计算主花色。
     * 支持 1张、2张、3张（两王+主）情况。
     *
     * @param cards 出的牌列表
     * @param zhuValue 主值（通常为2）
     * @return 主花色
     */
    public static int calcMainColor(List<Integer> cards, int zhuValue) {
        if (cards == null || cards.isEmpty()) {
            throw new GameOpException(GameErrorCode.INVALID_OP, "出牌列表不能为空!");
        }

        if (cards.size() == 3) {
            // 3张牌：两个王+一个主
            List<Integer> mainCards = cards.stream()
                    .filter(card -> getCardValueEx(card) == zhuValue)
                    .collect(Collectors.toList());

            if (mainCards.isEmpty()) {
                throw new GameOpException(GameErrorCode.INVALID_CARD, "三张牌中没有主牌");
            }
            return getCardColor(mainCards.get(0));
        } else {
            // 1张或2张：直接取第一张
            return getCardColor(cards.get(0));
        }
    }

    /**
     * 转换牌列表为 “红桃K, 梅花2, 小王” 格式字符串
     */
    public static String toCardString(Integer card) {
        return toCardString(Collections.singletonList(card));
    }

    public static List<String> toCardStringList(List<List<Integer>> cardGroups) {
        return cardGroups.stream()
                .map(BasePoker::toCardString)
                .collect(Collectors.toList());
    }

    public static Integer parseCard(String desc) {
        if (desc == null || desc.isEmpty()) return null;

        desc = desc.trim();

        if (desc.equals("大王")) return 0x42;
        if (desc.equals("小王")) return 0x41;

        int colorBase;
        if (desc.startsWith("方块")) {
            colorBase = 0x00;
        } else if (desc.startsWith("梅花")) {
            colorBase = 0x10;
        } else if (desc.startsWith("红桃")) {
            colorBase = 0x20;
        } else if (desc.startsWith("黑桃")) {
            colorBase = 0x30;
        } else {
            return null;
        }

        String valuePart = desc.substring(2).toUpperCase();
        int value;
        switch (valuePart) {
            case "A":
                value = 0x0E;
                break;
            case "K":
                value = 0x0D;
                break;
            case "Q":
                value = 0x0C;
                break;
            case "J":
                value = 0x0B;
                break;
            default:
                try {
                    value = Integer.parseInt(valuePart);
                    if (value == 10) value = 0x0A; // 显式支持10
                } catch (NumberFormatException e) {
                    return null;
                }
        }

        return colorBase + value;
    }

    public static String toCardGroupLog(Map<Integer, List<Integer>> map) {
        return map.entrySet().stream()
                .map(e -> "值=" + e.getKey() + " -> [" + BasePoker.toCardString(e.getValue()) + "]")
                .collect(Collectors.joining(" | "));
    }
}
